package com.kuaimacode.kframework.api.service;

import com.google.common.collect.Lists;
import com.kuaimacode.kframework.api.vo.response.UploadImgResp;
import com.kuaimacode.kframework.exception.ErrorEnum;
import com.kuaimacode.kframework.exception.ServerInternalErrorException;
import com.kuaimacode.kframework.util.CommonUtil;
import com.kuaimacode.kframework.util.DateUtil;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Service;
import org.springframework.web.multipart.MultipartFile;
import sun.misc.BASE64Decoder;

import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.OutputStream;
import java.util.ArrayList;
import java.util.List;

/**
 * @author qinyong
 * @Title:
 * @Package com.kuaimacode.kframework.api.service
 * @Description: created by IntelliJ IDEA
 * @date 2019-03-16 21:31
 */
@Slf4j
@Service
public class UploadService {

    @Value("${img.upload.location.root}")
    private String uploadRootLocation;
    @Value("${img.upload.location.img}")
    private String imgUploadLocation;
    @Value("${project.domain}")
    private String domain;

    /**
     * 上传身份证照片
     *
     * @param file
     * @param location
     * @param userId
     * @return
     */
    public UploadImgResp uploadIdCard(MultipartFile file, String location, Long userId) {
        String fileName = DateUtil.getNow(DateUtil.FORMAT_FOUR_MINUTE) + "_" + userId + location + getFileSuffix(file);
        saveFile(file, fileName);
        return buildImgResp(fileName);
    }

    /**
     * 上传实名认证的活体头部图片
     *
     * @param file
     * @param userId
     * @return
     */
    public UploadImgResp uploadCertiHead(MultipartFile file, Long userId) {
        String fileName = DateUtil.getNow(DateUtil.FORMAT_FOUR_MINUTE) + "_" + userId + "head" + getFileSuffix(file);
        saveFile(file, fileName);
        return buildImgResp(fileName);
    }

    /**
     * 批量上传
     *
     * @param base64
     * @param userId
     * @return
     */
    public List<UploadImgResp> batchUpload(List<String> base64, Long userId) {
        List<UploadImgResp> imgResps = new ArrayList<>();
        for (String pic : base64) {
            String imgSuffix = validImg(pic);
            String fileName = DateUtil.getNow(DateUtil.FORMAT_FOUR_MINUTE) + "_" + userId + "." + imgSuffix;
            String url = upload(fileName, pic);
            UploadImgResp imgResp = new UploadImgResp();
            imgResp.setName(fileName);
            imgResp.setUrl(url);
            imgResps.add(imgResp);
        }
        return imgResps;
    }

    public List<UploadImgResp> getPicUrl(String[] picName) {
        List<UploadImgResp> imgResps = new ArrayList<>();
        for (int i = 0; i < picName.length; i++) {
            String name = picName[i];
            UploadImgResp resp = new UploadImgResp();
            resp.setName(name);
            String url = domain + imgUploadLocation + name;
            resp.setUrl(url);
            imgResps.add(resp);
        }
        return imgResps;
    }

    public String getPicUrlPath(String picName) {
        String url = domain + imgUploadLocation + picName;
        return url;
    }


    /**
     * 上传图片
     *
     * @param file
     * @param userId
     * @return
     */
    public UploadImgResp uploadImg(MultipartFile file, Long userId) {
        String fileName = DateUtil.getNow(DateUtil.FORMAT_FOUR_MINUTE) + "_" + userId + "_" + (int) ((Math.random() * 9 + 1) * 1000) + getFileSuffix(file);
        saveFile(file, fileName);
        return buildImgResp(fileName);
    }

    private UploadImgResp buildImgResp(String fileName) {
        UploadImgResp imgResp = new UploadImgResp();
        imgResp.setName(fileName);
        imgResp.setUrl(domain + imgUploadLocation + fileName);
        return imgResp;
    }

    private String getFileSuffix(MultipartFile file) {
        return file.getOriginalFilename().substring(file.getOriginalFilename().lastIndexOf('.'));
    }

    private void saveFile(MultipartFile file, String fileName) {
        File destFile = new File(uploadRootLocation + imgUploadLocation + fileName);
        destFile.getParentFile().mkdirs();
        //5.把浏览器上传的文件复制到希望的位置
        try {
            file.transferTo(destFile);
        } catch (IOException e) {
            log.error(e.getMessage(), e);
            throw new ServerInternalErrorException(ErrorEnum.IMG_UPLOAD_ERROR);
        }
    }

    /**
     * 保存图片
     *
     * @param fileName
     * @param base64Img
     * @return
     */
    private String upload(String fileName, String base64Img) {
        if (uploadBase64(base64Img.substring(base64Img.indexOf(',') + 1), uploadRootLocation + imgUploadLocation + fileName)) {
            return domain + imgUploadLocation + fileName;
        }
        throw new ServerInternalErrorException(ErrorEnum.IMG_UPLOAD_ERROR);
    }

    private String validImg(String base64Img) {
        String imgSuffix = CommonUtil.getSuffixFromBase64(base64Img);
        List<String> allowSuffix = Lists.newArrayList("png", "jpeg", "jpg");
        if (!allowSuffix.contains(imgSuffix.toLowerCase())) {
            throw new ServerInternalErrorException(ErrorEnum.IMG_SUFFIX_NOT_ALLOW);
        }
        return imgSuffix;
    }

    /**
     * 保存base64图片
     *
     * @param imgStr
     * @param imgFilePath
     * @return
     */
    private boolean uploadBase64(String imgStr, String imgFilePath) {
        if (StringUtils.isEmpty(imgStr)) {
            return false;
        }

        BASE64Decoder decoder = new BASE64Decoder();
        try {
            // Base64解码
            byte[] b = decoder.decodeBuffer(imgStr);
            for (int i = 0; i < b.length; ++i) {
                if (b[i] < 0) {
                    b[i] += 256;
                }
            }

            try (OutputStream out = new FileOutputStream(imgFilePath)) {
                out.write(b);
                out.flush();
            }
            return true;
        } catch (Exception e) {
            log.error("base64保存图片失败", e);
            return false;
        }
    }
}
